Skip to content

Comments

Release v1.0.3: Multi-user support, dynamic user registry, chat archive#8

Merged
GoDoming merged 6 commits intomainfrom
dev
Feb 21, 2026
Merged

Release v1.0.3: Multi-user support, dynamic user registry, chat archive#8
GoDoming merged 6 commits intomainfrom
dev

Conversation

@GoDoming
Copy link
Member

What's new in v1.0.3

🧑‍🤝‍🧑 Central users table

  • New users table as canonical user registry (id, displayName, isAdmin, isAgent, avatarUrl)
  • Seeded initial team: chris, clio, domingo, zumie, gonzo
  • auth.ts: removed hardcoded validMailboxes set — loads from DB at startup
  • Invite redemption auto-creates a users row for new members
  • New admin endpoints: GET /api/admin/users, PATCH /api/admin/users/:id

🔄 Dynamic user lists

  • New GET /api/users — authenticated endpoint (non-admin) for fetching active users
  • New useUsers() / useUserIds() React hook with 5-min module-level cache
  • Replaced all hardcoded ALL_USERS / KNOWN_USERS / KNOWN_RECIPIENTS constants across: nav avatar bar, presence team list, presence group chat dialog, swarm assignee pickers, admin recurring task picker, compose dialog recipient quick-pick
  • Any new user added to the users table now appears everywhere automatically

🗄️ Chat archive (soft delete)

  • New archived_at column on chat_members (per-member — archiving only affects your view)
  • GET /api/chat/channels — supports ?archived=true to fetch archived chats
  • New POST /api/chat/channels/:id/archive and /unarchive endpoints
  • UI: hover any chat row → Archive icon replaces timestamp → click to archive
  • Archive toggle button in chat list header switches between active and archived views
  • Archived view shows ArchiveRestore icon to unarchive

DB migrations applied

CREATE TABLE users (...);
GRANT ALL ON TABLE users TO team_user;
ALTER TABLE chat_members ADD COLUMN archived_at TIMESTAMPTZ;

…tion

- Add users table (id, displayName, isAdmin, isAgent, avatarUrl, timestamps)
- Apply DB migration: CREATE TABLE + GRANT to team_user
- Seed initial users: chris, clio, domingo, zumie, gonzo
- auth.ts: remove hardcoded validMailboxes set, load from users table at startup
- auth.ts: export listUsers() for admin use
- register.post.ts: auto-upsert users row on invite redemption
- Add GET /api/admin/users — list users with presence enrichment
- Add PATCH /api/admin/users/:id — update user profile/status
- api.ts: add listUsers() and updateUser() client helpers
- Add GET /api/users — authenticated endpoint returning all active users
- Add useUsers() / useUserIds() React hook with 5-min module-level cache
- Replace ALL_USERS/KNOWN_USERS/KNOWN_RECIPIENTS constants in:
  - src/components/nav.tsx (presence avatar bar)
  - src/routes/presence.tsx (team list, group chat dialog)
  - src/routes/swarm.tsx (task assignee pickers, project lead pickers)
  - src/routes/admin.tsx (recurring task assignee picker)
  - src/components/compose-dialog.tsx (recipient quick-pick)
- Any new user added to the users table now automatically appears everywhere
…view

- Add archived_at column to chat_members (per-member, others unaffected)
- DB migration applied
- chat.ts: filter archived channels from default list; add archiveChannel/unarchiveChannel
- GET /api/chat/channels: support ?archived=true to fetch archived chats
- POST /api/chat/channels/:id/archive + /unarchive endpoints
- api.ts: archiveChat() / unarchiveChat() / listChatChannels(archived) client helpers
- presence.tsx: hover on chat row shows Archive icon (replaces timestamp)
  Archive button: removes from active list instantly
  Archived view: Archive icon in header toggles between active/archived
  ArchiveRestore icon in archived view to unarchive
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e42740a9aa

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

P1: user-select.tsx was spreading data.users (now HiveUser[]) directly
into a string[] — map to ids before merging with value set

P2: Boolean() coercion in admin PATCH endpoint would accept any
non-empty string as true for isAdmin/isAgent flags — now requires
strict boolean type, returns 400 on anything else
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 144f1b3ac9

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

P1 (auth.ts): archived users stay in validMailboxes until restart
- Add deregisterMailbox() to auth.ts
- PATCH /api/admin/users/:id now calls deregister/registerMailbox
  immediately when archivedAt is set/cleared — no restart needed

P2 (presence.tsx): hover-only archive button unreachable on touch
- Remove hoveredChannel state and mouse enter/leave handlers
- Archive icon always visible (text-muted-foreground/30, tap target)
  with hover:text-muted-foreground for desktop polish
- Timestamp shown alongside archive button at all times
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d2edc0175a

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

P1 (users.get.ts): env-token users missing from /api/users
- Export getEnvIdentities() from auth.ts
- /api/users merges DB users + env-only identities as minimal objects
  so all authenticated users appear in UI selectors regardless of
  whether they have a users table row

P1 (patch.ts): archived users kept working tokens
- On archive: revoke all mailboxTokens rows for that identity
  + clear DB auth cache — existing tokens immediately stop working
- On restore: re-add to validMailboxes + clear cache
  (revoked tokens stay revoked; admin must issue new tokens)
@GoDoming GoDoming merged commit 47295fc into main Feb 21, 2026
4 checks passed
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c22f9f11f5

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +103 to +105
.update(mailboxTokens)
.set({ revokedAt: new Date() })
.where(eq(mailboxTokens.identity, id));

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Block archived users with env-backed tokens

Archiving currently revokes only mailbox_tokens rows, but auth still accepts identities from envTokens (HIVE_TOKEN_*, MAILBOX_TOKEN_*, UI_MAILBOX_KEYS) and sender routes do not re-check sender validity against mailbox status, so an archived user with an env-configured token can continue authenticating and calling protected APIs after archival. To make deactivation effective, archival needs to block env-token auth for that identity (or auth must check users.archived_at before returning a context).

Useful? React with 👍 / 👎.

Comment on lines +24 to +25
.filter((id) => !dbIds.has(id))
.map((id) => ({

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Exclude archived env identities from /api/users

The env fallback compares against dbIds built from listUsers() (non-archived only), so if an identity is archived in users but still present in env tokens, it is reintroduced as an active user object here. That makes archived accounts reappear in user pickers and causes downstream send/archive UX inconsistencies because those accounts were intentionally deactivated. The merge should exclude any identity that exists in users at all, not just currently active ones.

Useful? React with 👍 / 👎.

Comment on lines +463 to +467
export const users = pgTable("users", {
id: varchar("id", { length: 50 }).primaryKey(), // = identity slug ("gonzo", "chris")
displayName: varchar("display_name", { length: 100 }).notNull(),
isAdmin: boolean("is_admin").notNull().default(false),
isAgent: boolean("is_agent").notNull().default(false), // true for AI agents

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Add a Drizzle migration for new user/chat schema

This change introduces new DB schema (users table and chat_members.archived_at) and immediately depends on it in runtime code, but no migration file was added under drizzle/ in this commit. Deployments that follow the documented db:migrate upgrade flow will keep the old schema and encounter runtime SQL failures when these queries run. A tracked migration is needed so upgrades apply the required DDL consistently.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants